package com.yy.okhttp;

import com.yy.okhttp.chain.HeaderInterceptor;
import com.yy.okhttp.chain.ConnectionInterceptor;
import com.yy.okhttp.chain.RetryInterceptor;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * User: gongyongfeng2@yy.com
 * Date: 2020/7/28 17 :32
 */
public class Call {
    private Request mRequest;
    private YYOkHttpClient mYYOkHttpClient;
    boolean executed;
    boolean canceled;

    public Call(YYOkHttpClient yyOkHttpClient, Request request) {
        mRequest = request;
        mYYOkHttpClient = yyOkHttpClient;
    }

    public Call enqueue(Callback callback) {
        synchronized (this) {
            if (executed) {
                throw new IllegalArgumentException(" already executed");
            }
            executed = true;
        }
        mYYOkHttpClient.dispatcher().enqueue(new AsyncCall(callback));
        return this;
    }

    public YYOkHttpClient client() {
        return mYYOkHttpClient;
    }

    public Request request() {
        return mRequest;
    }

    public void canceled() {
        canceled = true;
    }

    public boolean isCanceled() {
        return canceled;
    }

    private Response getResponse() throws IOException {
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.addAll(mYYOkHttpClient.interceptors());
        interceptors.add(new RetryInterceptor());
        interceptors.add(new HeaderInterceptor());
        interceptors.add(new ConnectionInterceptor());
        InterceptorChain interceptorChain = new InterceptorChain(interceptors, 0, this);
        return interceptorChain.proceed();
    }

    final class AsyncCall implements Runnable {

        private final Callback callback;

        public AsyncCall(Callback callback) {
            this.callback = callback;
        }

        @Override
        public void run() {
            //是否已经通知过callback
            boolean signalledCallback = false;
            try {
                Response response = getResponse();
                if (canceled) {
                    signalledCallback = true;
                    callback.onFailure(Call.this, new IOException("Canceled"));
                } else {
                    signalledCallback = true;
                    callback.onResponse(Call.this, response);
                }
            } catch (IOException e) {
                if (!signalledCallback) {
                    callback.onFailure(Call.this, e);
                }
            } finally {
                mYYOkHttpClient.dispatcher().finished(this);
            }
        }

        public String host() {
            return mRequest.getUrl().host;
        }
    }
}
